package org.robot.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.jsoup.helper.StringUtil;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.robot.component.Page;

public class Utils {
//	private static String nameRegex = "[a-zA-Z]+[-\\D.]*([\u00A0\\s]+\\D+\\.*)*";
	private static String nameRegex = "[a-zA-Z]+[-[^(\\p{Punct}0-9)].]*([\u00A0\\s]+[^(\\p{Punct}0-9)]+\\.*)*";
	
	/**
	 * 返回author和affli的键值对
	 * @param authors
	 * @param autDelimiter 作者之间的分隔符
	 * @param afflis 单位的字符串，每个单位以标志开头
	 * @param affliDelimiter 单位之间的分隔符
	 * @param containAutDelimiterRegex 包含作者分隔符的正则
	 * @return
	 */
	public static Map<String, String> autAffMap(String authors, String autDelimiter, String afflis, String affliDelimiter, String... containAutDelimiterRegex) {
		Map<String, String> map = new HashMap<String, String>();
		String[] authorArr = null;
		if (containAutDelimiterRegex != null && containAutDelimiterRegex.length > 0) {
			authors = RegexUtil.replaceSpecified(authors, containAutDelimiterRegex[0], autDelimiter, "!;");
			authorArr  = authors.split("!;| and ");
		} else
			authorArr  = authors.split(autDelimiter + "| and ");
		String[] affliArr = afflis.split(affliDelimiter);
		for (String autStr : authorArr) {
			if (StringUtil.isBlank(autStr))
				continue;
			String aut = RegexUtil.regexFirst(nameRegex, autStr).replaceAll("\n|\r", "");
			map.put(aut, matchAffli(autStr.replace(aut, ""), affliArr));
		}
		return map;
	}
	
	/**
	 * 返回author和affli的键值对
	 * @param authors 以分隔符分隔的作者字符串
	 * @param autDelimiter 作者之间的分隔符
	 * @param affliEles 其中的每个单位应以标志开头
	 * @param containAutDelimiterRegex 包含作者分隔符的正则
	 * @return
	 */
	public static Map<String, String> autAffMap(String authors, String autDelimiter, Elements affliEles, String... containAutDelimiterRegex) {
		Map<String, String> map = new HashMap<String, String>();
		String[] authorArr = null;
		if (containAutDelimiterRegex != null && containAutDelimiterRegex.length > 0) {
			authors = RegexUtil.replaceSpecified(authors, containAutDelimiterRegex[0], autDelimiter, "!;");
			authorArr  = authors.split("!;| and ");
		} else
			authorArr  = authors.split(autDelimiter + "| and ");
		
		List<String> affliList = new ArrayList<String>(affliEles.size());
		for (Element affliEle : affliEles) {
			String affli = affliEle.text();
			if (!StringUtil.isBlank(affli))
				affliList.add(affli);
		}
		String[] affliArr = affliList.toArray(new String[affliList.size()]);
		for (String autStr : authorArr) {//[a-zA-Z.]+([\u00A0\\s]+[a-zA-Z]+\\.*)*
			if (StringUtil.isBlank(autStr))
				continue;
			String aut = RegexUtil.regexFirst(nameRegex, autStr).replaceAll("\n|\r", "");
			if (StringUtil.isBlank(aut))
				continue;
			map.put(aut, matchAffli(autStr.replace(aut, ""), affliArr));
		}
		return map;
	}
	

	private static String matchAffli(String containsAutFlag, String[] affliArr) {
		String affli = "";
		if (affliArr.length == 1)
			return affliArr[0];
		for (String affliStr : affliArr) {
			String affliFlag = affliStr.substring(0, 1);
			if (containsAutFlag.contains(affliFlag))
				affli += "^" + affliStr.substring(1).replace("*", "").trim();
		}
		return affli.replaceFirst("\\^", "");
	}

	

	/**
	 * 返回author和affli的键值对
	 * 处理这样的：http://ascopubs.org/doi/abs/10.1200/PO.17.00037
	 * authorElement没有标识，单位之间用;分隔，单位以作者名字区别
	 * @param autEles 作者elements
	 * @param affliStr 单位字符串
	 * @return
	 */
	public static Map<String, String> autAffMap(Elements autEles, String affliStr) {
		Map<String, String> map = new HashMap<String, String>(autEles.size());
		for (Element autEle : autEles) {
			String aut = RegexUtil.regexFirst(nameRegex, autEle.text()).replaceAll("\n|\r", "");
			String aff = getAff(aut, affliStr);
			map.put(aut, aff);
		}
		return map;
	}
	private static String getAff(String aut, String affliStr) {
		if (StringUtil.isBlank(affliStr))
			return null;
		else if (!affliStr.contains(";"))
			return affliStr;
		String[] affArr = affliStr.split(";");
		for (String aff : affArr) {
			if (aff.contains(aut)) {
				String[] affInfoArr = aff.split(",");
				for (String affInfo : affInfoArr) {
					if (!affInfo.contains(aut))
						return affInfo;
				}
			}
		}
		return affliStr;
	}

	/**
	 * 返回author和affli的键值对
	 * @param autEles 作者elements
	 * @param autSupSelector 包含在每个作者中的标志element
	 * @param affEles 单位elements
	 * @param affSupSelector 包含在每个单位 是的标志element
	 * @return
	 */
	public static Map<String, String> getAutAffMap(Elements autEles, String autSupSelector, Elements affEles, String affSupSelector) {
		Map<String, String> map = new HashMap<String, String>(autEles.size());
		for (Element autEle : autEles) {
			String author = null; 
			for (Element autChildEle : autEle.children()) {
				String text = autChildEle.text().trim();
				if (text.matches(nameRegex)) 
					author = text.replaceAll("\n|\r", "");
			}
			String autSup = autEle.select(autSupSelector).text();
			String aff = getAff(autSup, affEles, affSupSelector);
			map.put(author, aff);
		}
		return map;
	}

	private static String getAff(String autSup, Elements affEles, String affSupSelector) {
//		return affEles.stream().filter(affEle -> autSup.contains(affEle.select(affSupSelector).text()))
//				.map(affEle -> affEle.text().replaceFirst(affEle.select(affSupSelector).text(), "").replace("*", "").trim())
//				.collect(Collectors.joining(" ^ "));
		String affliStr = "";
		for (Element affEle : affEles) {
			String affSupText = affEle.select(affSupSelector).text();
			if (autSup.contains(affSupText)) {
				affliStr += ("^" + affEle.text().replaceFirst(affSupText, "").replace("*", "").trim());
			}
		}
		return affliStr.replaceFirst("\\^", "");
	}

	
	/**
	 * 返回作者邮箱map，该方法只返回能匹配到email的aut-email的map，也就是说返回的map的键集合不一定是全部的作者
	 * 适合于href^=mailto的
	 * @param authorSet
	 * @param page
	 * @return
	 */
	public static Map<String, String> getAutEmailMap(Set<String> authorSet, Page page) {
		Elements emailEles = page.select("a[href^=mailto]");
		String[] emailArr = new String[emailEles.size()]; 
		for (int i = 0; i < emailEles.size(); i++) {
			emailArr[i] = emailEles.get(i).text().trim();
		}
		return getAutEmailMap(authorSet, emailArr);
	}
	
	/**
	 * 返回作者邮箱map，该方法只返回能匹配到email的author-email的map，也就是说返回的map的键集合不一定是全部的作者
	 * @param authorSet
	 * @param emailArr
	 * @return
	 */
	public static Map<String, String> getAutEmailMap(Collection<String> authorSet, String[] emailArr) {
		String[] authors = authorSet.toArray(new String[authorSet.size()]);
		return getAutEmailMap(authors, emailArr);
	}
	
	/**
	 * 返回作者邮箱map，该方法只返回能匹配到email的aut-email的map，也就是说返回的map的键集合不一定是全部的作者
	 * @param authors
	 * @param emailArr
	 * @return
	 */
	public static Map<String, String> getAutEmailMap(String[] authors, String[] emailArr) {
		Map<String, String> map = new HashMap<String, String>(emailArr.length);
		for (String email : emailArr) {
			String matchAut = MatchEmail.similarName(authors, email);
//			authors = removeMatchAuthor(authors, matchAut);//如果一个人多个邮箱就不能加这个
			map.put(matchAut, email.toLowerCase());
		}
		return map;
	}
	
	/**
	 * 返回作者邮箱map，该方法只返回能匹配到email的aut-email的map，也就是说返回的map的键集合不一定是全部的作者
	 * 适合于href^=mailto的
	 * @param authorSet
	 * @param page
	 * @return
	 */
	public static Map<String, String[]> getAutEmailArrMap(Set<String> authorSet, Page page) {
		Elements emailEles = page.select("a[href^=mailto]");
		String[] emailArr = new String[emailEles.size()]; 
		for (int i = 0; i < emailEles.size(); i++) {
			emailArr[i] = emailEles.get(i).text().trim();
		}
		return getAutEmailArrMap(authorSet, emailArr);
	}
	
	/**
	 * 返回作者邮箱map，该方法只返回能匹配到email的author-email的map，也就是说返回的map的键集合不一定是全部的作者
	 * @param authorSet
	 * @param emailArr
	 * @return
	 */
	public static Map<String, String[]> getAutEmailArrMap(Collection<String> authorSet, String[] emailArr) {
		String[] authors = authorSet.toArray(new String[authorSet.size()]);
		return getAutEmailArrMap(authors, emailArr);
	}
	
	/**
	 * 返回作者邮箱map，该方法只返回能匹配到email的aut-email的map，也就是说返回的map的键集合不一定是全部的作者
	 * @param authors
	 * @param emailArr
	 * @return
	 */
	public static Map<String, String[]> getAutEmailArrMap(String[] authors, String[] emailArr) {
		Map<String, String[]> map = new HashMap<String, String[]>(emailArr.length);
		for (String email : emailArr) {
			String matchAut = MatchEmail.similarName(authors, email);
//			authors = removeMatchAuthor(authors, matchAut);//如果一个人多个邮箱就不能加这个
			String[] emails = map.get(matchAut);
			if (emails == null)
				map.put(matchAut, new String[]{email});
			else {
				String[] newEmails = Arrays.copyOf(emails, emails.length + 1);
				newEmails[newEmails.length-1] = email;
				map.put(matchAut, newEmails);
			}
		}
		return map;
	}
	
//	private static String[] removeMatchAuthor(String[] authors, String matchAut) {
//		String[] noneMatchAuthorArr = new String[authors.length - 1];
//		for (int i = 0, j = 0; i < authors.length; i++, j++) {
//			if (authors[i].equals(matchAut)) {
//				j--;
//				continue;
//			}
//			noneMatchAuthorArr[j] = authors[i];
//		}
//		return noneMatchAuthorArr;
//	}

	/**
	 * 得到baseurl，不是以/结尾的
	 * @param url
	 * @return
	 */
	public static String getBaseUrl(String url) {
		return url.substring(0, url.indexOf("/", url.indexOf("//")+2));
	}
	
	/**
	 * 将处理后的字符串还原成邮箱，适用于下面的网站
	 * http://www.alliedacademies.org/articles/novel-anticoagulants-following-biological-valve-implantations-a-new-hope-with-lacking-evidence.html
	 * https://www.omicsonline.org/proceedings/catalytic-oxidation-and-enhanced-production-of-oxidoreductases-for-polymer-degradation-56489.html
	 * @param s
	 * @return
	 */
	public static String dealEmail(String s) {
		try {
			StringBuffer sb = new StringBuffer();
			int v = Integer.parseInt(s.substring(0, 2), 16);
			for (int i = 0; i < s.length(); i += 2) {
				int k = Integer.parseInt(s.substring(i, i + 2), 16);
				sb.append((char) (k ^ v));
			}
			return sb.toString().trim();
		} catch (Exception e) {
			return "";
		}
	}
	
//	public static Links customUrlEncode(Links links) {
//		Links newLinks = new Links();
//		for (String link : links) {
//			link = link.replace(" ", "%20");
//			newLinks.add(link);
//		}
//		return newLinks;
//	}
	
	public static void main(String[] args) {
		System.out.println(dealEmail("c5acb6adac9aa4a9ac85adaab1a8a4aca9eba6aaa8"));
	}

	/**
	 * 添加指定的分隔符，将元素的文本值转化成字符串
	 * @param eles 元素
	 * @param separator 分隔符
	 * @return
	 */
	public static String string(Elements eles, String separator) {
	    if (eles == null || eles.isEmpty())
	        return null;
		String str = eles.first().text();
		for (int i = 1; i < eles.size(); i++) {
			str += separator + eles.get(i).text();
		}
		return str;
	}
	
	/**
	 * 添加指定的分隔符，将元素的属性值转化成字符串
	 * @param eles 元素
	 * @param separator 分隔符
	 * @param attr 属性
	 * @return
	 */
	public static String stringAttr(Elements eles, String separator, String attr) {
		String str = eles.get(0).attr(attr);
		for (int i = 1; i < eles.size(); i++) {
			str += separator + eles.get(i).attr(attr);
		}
		return str;
	}

	/**
	 * 返回作者-邮箱的map
	 * @param autEmailStr 包含作者和邮箱的字符串
	 * @param autEles 作者标签，文本就是作者名字
	 * @param replaceRegex 去除名字中的无用字符串
	 * @return
	 */
	public static Map<String, String> autEmailMap(String autEmailStr, Elements autEles, String... replaceRegex) {
		String[] autArr = new String[autEles.size()];
		for (int i = 0; i < autArr.length; i++) {
			String aut = autEles.get(i).text();
			if (replaceRegex != null)
				aut = aut.replaceAll(replaceRegex[0], "");
			autArr[i] = aut;
		}
		if (replaceRegex == null)
			replaceRegex = new String[]{""};
		return autEmailMap(autEmailStr, autArr, replaceRegex[0]);
		
		
//		Map<String, String> map = new HashMap<>();
//		for (Element autEle : autEles) {
//			String aut = autEle.text();
//			if (replaceRegex != null)
//				aut = aut.replaceAll(replaceRegex[0], "");
//			int autIndex = autEmailStr.indexOf(aut);
//			String email = null;
//			if (autIndex > -1) {
//				String subStr = autEmailStr.substring(autIndex);
//				email = FileCommon.getFirstEmail(subStr);
//			}
//			if (!StringUtil.isBlank(aut))
//				map.put(aut, email);
//		}
//		return map;
	}
	
	/**
	 * 从email索引开始向前推进，从而匹配作者
	 * 返回作者-邮箱的map,包括没有匹配到邮箱的作者
	 * @param autEmailStr 包含作者和邮箱的字符串
	 * @param autEles
	 * @param emailArr 全部小写的email数组
	 * @return
	 */
	public static Map<String, String> autEmailMap(String autEmailStr, String[] auts, String replaceRegex) {
		Set<String> emailSet = MatchEmail.getEmailByStr(autEmailStr);
		String[] emailArr = emailSet.toArray(new String[emailSet.size()]);
		return autEmailMap(autEmailStr, auts, emailArr, 0, replaceRegex);
	}
	
	/**
	 * 从email索引开始向前推进，从而匹配作者
	 * 返回作者-邮箱的map,包括没有匹配到邮箱的作者
	 * @param autEmailStr 包含作者和邮箱的字符串
	 * @param autEles
	 * @param emailArr 全部小写的email数组
	 * @param space 距离email索引的距离，如果小于等于0则一直搜索到开头
	 * @return
	 */
	public static Map<String, String> autEmailMap(String autEmailStr, String[] auts, String[] emailArr, int space, String replaceRegex) {
		autEmailStr = autEmailStr.toLowerCase();
		Map<String, String> map = new HashMap<String, String>();
		int maxAutLength = 0;
		for (int i = 0; i < auts.length; i++) {
			String aut = auts[i].replaceAll(replaceRegex, "");
			maxAutLength = (maxAutLength > aut.length() ? maxAutLength : aut.length());
			if (!StringUtil.isBlank(aut))
				map.put(aut, null);
		}
		for (String email : emailArr) {
			int emailIndex = autEmailStr.indexOf(email);
			int endIndex = space <= 0 ? 0 : emailIndex - maxAutLength - space;
			endIndex = endIndex < 0 ? 0 : endIndex;
			for (int i = emailIndex-1; i >= endIndex; i--) {
				String subStr = autEmailStr.substring(i, emailIndex);
				String matchAut = matchAut(map, subStr);
				if (matchAut != null) {
					map.put(matchAut, email);
					break;
				}
			}
		}
		return map;
	}

	private static String matchAut(Map<String, String> map, String subStr) {
		for (String aut : map.keySet()) {
			if (subStr.contains(aut.toLowerCase()) || subStr.contains(aut))
				return aut;
		}
		return null;
	}
	
	/**
	 * 用于http://hub.hku.hk/advanced-search?location=publication这个网站
	 * @param autArr
	 * @param emailArr
	 * @param page
	 * @return
	 */
	public static Map<String, String[]> getAutEmailArrMap(String[] autArr, String[] emailArr, Page page) {
		Map<String, String[]> map = new HashMap<String, String[]>(emailArr.length);
		Map<String, String> autEmailMap = autEmailMap(page.html(), autArr, emailArr, 5, "");
		for (Entry<String, String> e : autEmailMap.entrySet()) {
			String aut = e.getKey();
			String email = e.getValue();
			String[] emails = email == null ? null : new String[]{email};
			map.put(aut, emails);
			otherMatchEmails(map, autEmailMap, e, emailArr);
		}
		return map;
	}

	private static Map<String, String[]> otherMatchEmails(
			Map<String, String[]> map, Map<String, String> autEmailMap,
			Entry<String, String> autEmailEntry, String[] emailArr) {
		
		Set<String> autSet = autEmailMap.keySet();
		String[] autArr = autSet.toArray(new String[autSet.size()]);
		String aut = autEmailEntry.getKey();
		String email = autEmailEntry.getValue();
		String pre = (email == null ? null : email.substring(0, email.indexOf("@")));
		for (String e : emailArr) {
			if (StringUtil.isBlank(e) || !e.contains("@"))
				continue;
			String tempPre = e.substring(0, e.indexOf("@"));
			if (!autEmailMap.containsValue(e)) {
				if (pre != null && pre.equals(tempPre)) {
					doPut(map, aut, e);
//					String[] emails = map.get(aut);
//					String[] emails1 = Arrays.copyOf(emails, emails.length + 1);
//					emails1[emails1.length - 1] = e;
//					map.put(aut, emails1);
				} else {
					//匹配
					String matchAut = MatchEmail.similarName(autArr, e);
//					String[] emails = map.get(matchAut);
//					String[] emails1 = Arrays.copyOf(emails, emails.length + 1);
//					emails1[emails1.length - 1] = e;
//					map.put(aut, emails1);
					doPut(map, matchAut, e);
				}
			}
		}
		return map;
	}

	private static void doPut(Map<String, String[]> map, String key, String value) {
		String[] values = map.get(key);
		if (values == null) {
			map.put(key, new String[]{value});
		} else {
			boolean exists = false;//是否已经存在
			for (String v : values) { 
				if (v.equals(value)) {
					exists = true;
					break;
				}
			}
			if (!exists) {
				String[] values1 = Arrays.copyOf(values, values.length + 1);
				values1[values1.length - 1] = value;
				map.put(key, values1);
			}
		}
	}

}
